﻿using Fish.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace MassiveBattle
{
	public class UI : MonoBehaviour, Manager.IWorker
	{
		public Manager.BaseManager Manager { get; private set; }

		[SerializeField]
		private UILabel namePlayerLabel;
		[SerializeField]
		private UILabel nameEnemyLabel;

		[SerializeField]
		private UISprite portraitPlayerSprite;
		[SerializeField]
		private UISprite portraitEnemySprite;

		[SerializeField]
		private UILabel[] leftTimeLabel;

		[SerializeField]
		private UILabel countPlayerTotal;
		[SerializeField]
		private UILabel countPlayer;

		[SerializeField]
		private float hpSliderTime = 10f;
		[SerializeField]
		private UISliderArray[] hpSlider;
		[SerializeField]
		private UISprite[] hpSliderThumb;
		[SerializeField]
		private Transform[] hpSliderThumbPresetRoot;
		private List<UISprite>[] hpSliderThumbPresetList;
		private IEnumerator[] hpSliderEnumerator = new IEnumerator[ESide.END];

		[SerializeField]
		private Transform[] tacticsMenu;
		[SerializeField]
		private UISlider[] tacticsSlider;
		[SerializeField]
		private Transform[] tacticsCountToggle;

		[SerializeField]
		private UIToggle x4Toggle;

		[SerializeField]
		private GameObject effectNotification;
		[SerializeField]
		private GameObject[] effectHpDecrease;
		[SerializeField]
		private GameObject effectUnitDieNoti;
		private List<GameObject> effectUnitDieNotiList = new List<GameObject>();

		[SerializeField]
		private BattleResultUI uiBattleResult;

		public string NamePlayer
		{
			set
			{
				namePlayerLabel.text = value;
			}
		}
		public string NameEnemy
		{
			set
			{
				nameEnemyLabel.text = value;
			}
		}

		public float LeftTimeCur
		{
			set
			{
				int i = Mathf.FloorToInt(value);

				leftTimeLabel[0].text = i.ToString();
				leftTimeLabel[1].text = Mathf.FloorToInt((value - i) * 100f).ToString("00");
			}
		}

		public float HpPlayer
		{
			set
			{
				SetHp(ESide.PLAYER, value);
			}
		}
		public float HpEnemy
		{
			set
			{
				SetHp(ESide.ENEMY, value);
			}
		}

		public int CountPlayerTotal
		{
			set
			{
				countPlayerTotal.text = value.ToString("00");
			}
		}
		public int CountPlayer
		{
			set
			{
				countPlayer.text = value.ToString("00");

				if (value <= 5)
					countPlayer.color = Color.red;

				countPlayer.transform.parent.animation.Play();
			}
		}

		public float TacticsRatioCur
		{
			set
			{
				tacticsSlider[0].value = value;

				float width = (tacticsSlider[0].foregroundWidget.width - tacticsSlider[0].foregroundWidget.minWidth) * tacticsSlider[0].value;
				Vector3 position = tacticsSlider[0].transform.localPosition;

				position.x += tacticsSlider[0].foregroundWidget.border.x + width;

				tacticsSlider[1].transform.localPosition = position;
				tacticsSlider[1].value = width / tacticsSlider[1].foregroundWidget.width;
			}
		}
		public int TacticsCountCur
		{
			set
			{
				for (int i = 0; i < Manager.TacticsCount; i++)
					tacticsCountToggle[i].Find("slot_on").gameObject.SetActive(i < value);
			}
		}
		public ETactics TacticsActive
		{
			set
			{
				if (value == ETactics.NONE)
				{
					foreach (var menu in tacticsMenu)
						menu.Find("press").gameObject.SetActive(false);

					return;
				}

				GameObject target = tacticsMenu[(int)value - 1].Find("press").gameObject;
				target.SetActive(true);
				target.animation.Play();
			}
		}
		public bool IsCanUseTactics
		{
			set
			{
				foreach (var menu in tacticsMenu)
					menu.Find("on").gameObject.SetActive(value);
			}
		}

		public bool IsX4ButtonActive
		{
			set
			{
				x4Toggle.collider.enabled = value;
			}
		}

		public bool IsActive
		{
			get
			{
				return gameObject.activeInHierarchy;
			}

			set
			{
				gameObject.SetActive(value);
			}
		}

		private void Awake()
		{
			hpSliderThumbPresetList = new List<UISprite>[hpSliderThumbPresetRoot.Length];

			for (int i = 0; i < hpSliderThumbPresetRoot.Length; i++)
				hpSliderThumbPresetList[i] = hpSliderThumbPresetRoot[i].OfType<Transform>().OrderBy(data => float.Parse(data.name)).Select(data => data.GetComponent<UISprite>()).ToList();
		}

		public void SetManager(Manager.BaseManager manager)
		{
			Manager = manager;
		}

		public void SetPortraitPlayer(Controller.BaseController source)
		{
			PortraitControl.SetBattlePortraitWithClass(portraitPlayerSprite, source.ClassName);
		}

		public void SetPortraitEnemy(Controller.BaseController source)
		{
			PortraitControl.SetBattlePortraitWithClass(portraitEnemySprite, source.ClassName);
		}

		private void SetHp(ESide side, float value)
		{
			SetHp(side, value, hpSliderTime);
		}

		public void SetHp(ESide side, float value, float time)
		{
			if (BattleManager.Instance != null && BattleManager.Instance.bOverdriveMode)
				return;

			if (!IsActive)
				return;

			if (hpSliderEnumerator[side] != null)
				StopCoroutine(hpSliderEnumerator[side]);

			hpSliderEnumerator[side] = SetHpCoroutine(side, hpSlider[side], hpSliderThumb[side], hpSliderThumbPresetList[side], hpSlider[side][0].value, value, time);

			StartCoroutine(hpSliderEnumerator[side]);
		}

		private IEnumerator SetHpCoroutine(ESide side, ArrayWrapper<UISlider> slider, UISprite thumb, List<UISprite> thumbPresetList, float start, float end, float time)
		{
			thumb.alpha = 1;

			for (float timeCur = 0f, timeTotal = start == end ? 0f : Mathf.Abs(end - start) * time; ; timeCur += Time.deltaTime)
			{
				float value = slider[0].value = Mathf.Lerp(start, end, timeTotal == 0f ? 1f : timeCur / timeTotal);
				float width = slider[0].foregroundWidget.width * value;

				if (side == ESide.PLAYER)
				{
					for (int i = 1; i < slider.Length; i++)
						slider[i].value = (width - slider[i].foregroundWidget.leftAnchor.absolute) / slider[i].foregroundWidget.width;
				}
				else
				{
					for (int i = 1; i < slider.Length; i++)
						slider[i].value = (width + slider[i].foregroundWidget.rightAnchor.absolute) / slider[i].foregroundWidget.width;
				}

				SetHpSliderThumb(value, thumb, thumbPresetList);

				if (timeCur > timeTotal)
					break;

				yield return null;
			}

			for (float timeCur = 0f, timeTotal = 0.4f; ; timeCur += Time.deltaTime)
			{
				thumb.alpha = Mathf.Lerp(1f, 0f, timeCur / timeTotal);

				if (timeCur > timeTotal)
					break;

				yield return null;
			}

			hpSliderEnumerator[side] = null;
		}

		private void SetHpSliderThumb(float value, UISprite thumb, List<UISprite> thumbPresetList)
		{
			float start = thumbPresetList[0].transform.localPosition.z, end;

			for (int i = 0; i < thumbPresetList.Count - 1; start = end, i++)
			{
				end = thumbPresetList[i + 1].transform.localPosition.z;

				if (value < start || value > end)
					continue;

				float ratio = (value - start) / (end - start);

				Vector3 position = Vector3.Lerp(thumbPresetList[i].transform.position, thumbPresetList[i + 1].transform.position, ratio);
				position.z = 0f;

				thumb.transform.position = position;
				thumb.height = Mathf.CeilToInt(Mathf.Lerp(thumbPresetList[i].height, thumbPresetList[i + 1].height, ratio));

				break;
			}
		}

		public void OnHealTacticsButtonClick(GameObject button)
		{
			if (!Manager.IsActive || !Manager.IsCanUseTactics)
				return;

			Manager.ExecuteHealTactics();

			button.audio.Play();
		}

		public void OnDefenceTacticsButtonClick(GameObject button)
		{
			if (!Manager.IsActive || !Manager.IsCanUseTactics)
				return;

			Manager.ExecuteDefenceTactics();

			button.audio.Play();
		}

		public void OnAttackTacticsButtonClick(GameObject button)
		{
			if (!Manager.IsActive || !Manager.IsCanUseTactics)
				return;

			Manager.ExecuteAttackTactics();

			button.audio.Play();
		}

		public void OnX4ButtonPress()
		{
			x4Toggle.enabled = true;
			x4Toggle.value = true;
			x4Toggle.enabled = false;

			EventlineTimeScale.Multiply = 4;

			if (CamTakeSetting.Instance != null)
			{
				CamTakeSetting.Instance.allowTouchCam = false;
				CamTakeSetting.Instance.DeactivateFreeCam();
			}
		}

		public void OnX4ButtonRelease()
		{
			x4Toggle.enabled = true;
			x4Toggle.value = false;
			x4Toggle.enabled = false;

			EventlineTimeScale.Multiply = 1;

			if (CamTakeSetting.Instance != null)
			{
				CamTakeSetting.Instance.allowTouchCam = true;
			}
		}

		public void ShowNofiticationEffect(string text, Action onEndEvent = null)
		{
			if (!IsActive)
				return;

			GameObject effect = Instantiate(effectNotification) as GameObject;

			effect.transform.parent = transform.parent;
			effect.transform.localPosition = Vector3.zero;
			effect.transform.localRotation = Quaternion.identity;
			effect.transform.localScale = Vector3.one;
			effect.transform.Find("text").GetComponent<UILabel>().text = text;

			StartCoroutine(ShowNotificationEffectCoroutine(effect, onEndEvent));
		}

		private IEnumerator ShowNotificationEffectCoroutine(GameObject effect, Action onEndEvent)
		{
			yield return new WaitForSeconds(effect.animation.clip.length);

			if (onEndEvent != null)
				onEndEvent();

			Destroy(effect);
		}

		public void ShowHpDecreaseEffect(ESide side)
		{
			if (!IsActive)
				return;

			GameObject effect = null;
			if (Manager != null)
				effect = Manager.GameObjectPool[effectHpDecrease[side]];
			else
				effect = Instantiate(effectHpDecrease[side]) as GameObject;
			Transform target = hpSliderThumb[side].transform;

			effect.transform.parent = transform.parent;
			effect.transform.position = target.position;
			effect.transform.localRotation = Quaternion.identity;
			effect.transform.localScale = Vector3.one;

			StartCoroutine(ShowHpDecreaseEffectCoroutine(effect));
		}

		private IEnumerator ShowHpDecreaseEffectCoroutine(GameObject effect)
		{
			yield return new WaitForSeconds(4f);
			if (Manager != null)
				Manager.GameObjectPool.Release(effect);
			else
				Destroy(effect, 4f);
		}

		public void ShowUnitDieNotiEffect(Controller.BaseController source)
		{
			if (!IsActive)
				return;

			var effect = NGUITools.AddChild(transform.parent.gameObject, effectUnitDieNoti);

			effect.transform.localPosition += Vector3.down * effectUnitDieNotiList.Count * 102f;
			effect.transform.Find("ani").animation.Play();
			effect.transform.Find("ani/Notice_Death/name").GetComponent<UILabel>().text = TextController.GetStringWithId(string.Format("charName{0}", source.Name));
			PortraitControl.SetBattlePortraitWithClass(effect.transform.Find("ani/Notice_Death/portrait").GetComponent<UISprite>(), source.ClassName);

			int overflow = effectUnitDieNotiList.Count - 3;
			if (overflow > 0)
			{
				for (int i = 0; i < effectUnitDieNotiList.Count; i++)
				{
					if (i < overflow)
						Destroy(effectUnitDieNotiList[i]);
					else
						effectUnitDieNotiList[i].transform.localPosition += Vector3.up * overflow * 102f;
				}

				effectUnitDieNotiList.RemoveRange(0, overflow);
			}

			effectUnitDieNotiList.Add(effect);

			StartCoroutine(ShowUnitDieNotiEffectCoroutine(effect));
		}

		private IEnumerator ShowUnitDieNotiEffectCoroutine(GameObject effect)
		{
			yield return new WaitForSeconds(effect.transform.Find("ani").animation.clip.length);

			if (effect != null)
			{
				effectUnitDieNotiList.Remove(effect);

				Destroy(effect);
			}
		}

		public void ShowBattleResult(Report report)
		{
			IsActive = false;

			GameObject obj = Instantiate(uiBattleResult.gameObject) as GameObject;
            SoundController.PlaySound("UI_Result_battle");

			obj.transform.parent = transform.parent;
			obj.transform.localPosition = Vector3.zero;
			obj.transform.localRotation = Quaternion.identity;
			obj.transform.localScale = Vector3.one;

			BattleResultUI popup = obj.GetComponent<BattleResultUI>();

			if (UserData.Instance.userModel.id > 0)
			{
				if (report.GetBattleResult())
					popup.Init(report, ShowBattleReward);
				else
					popup.Init(report, ShowBattleLose);
			}
			else
				popup.Init(report, null);
		}

		public void ShowBattleReward()
		{
			SoundController.PlayBGM("BGM_Battle_Win", false);

			GameObject popupPrefab = ResourceLoader.Load("Prefab/UI/battle_bossresult_popup_01") as GameObject;
			BossBattleResultPopup popup = (Instantiate(popupPrefab) as GameObject).GetComponent<BossBattleResultPopup>();
			popup.transform.parent = transform.parent;
			popup.transform.localScale = Vector3.one;
			popup.transform.localPosition = new Vector3(0f, 130f, 0f);
			if (UserData.Instance.raidBossResultData != null)
			{
				popup.legionExp.text = string.Format("+{0}", UserData.Instance.raidBossResultData.legionExp.ToString());
				if (UserData.Instance.raidBossResultData.discoverLegionId == UserData.Instance.userModel.id)
				{
					popup.rewardOffObject[0].SetActive(false);
					popup.rewardOffObject[1].SetActive(false);
					popup.rewardOffObject[2].SetActive(false);
					popup.rewardOnObject[0].SetActive(true);
					popup.rewardOnObject[1].SetActive(true);
					popup.rewardOnObject[2].SetActive(true);
				}
				else
				{
					popup.rewardOffObject[0].SetActive(true);
					popup.rewardOffObject[1].SetActive(false);
					popup.rewardOffObject[2].SetActive(false);
					popup.rewardOnObject[0].SetActive(false);
					popup.rewardOnObject[1].SetActive(true);
					popup.rewardOnObject[2].SetActive(true);
				}
			}

			//(지스타 임시) 임시테이블에 따라 보상 표시
			DGStarBossList info = GameData.Inst.GetGStarBossListByRegionId(WorldSceneManager_GStar.sentResearchAreaId);
			if (info != null)
			{
				if (info.gold != 0)
				{
					popup.rewardOnObject[0].SetActive(true);
					popup.rewardOffObject[0].SetActive(false);
				}
				if (info.charReward[0] != 0)
				{
					popup.rewardOnObject[1].SetActive(true);
					popup.rewardOffObject[1].SetActive(false);
				}
				if (info.itemReward[0] != 0)
				{
					popup.rewardOnObject[2].SetActive(true);
					popup.rewardOffObject[2].SetActive(false);
				}

				popup.legionExp.text = string.Format("+{0}", info.legionExp.ToString());
			}

			if (UserData.Instance.battleFriendId == 0)
			{
				popup.addFriendObject.SetActive(false);
				popup.friendRewardObject.SetActive(false);
			}
			else
			{
				if (UserData.Instance.battleFriendIsMyFriend)
				{
					popup.addFriendObject.SetActive(false);
					popup.friendRewardObject.SetActive(true);
				}
				else
				{
					popup.addFriendLabel.text = TextController.GetStringWithId("uiPopupFriendCaution1").Replace("{0}", UserData.Instance.battleFriend.lv.ToString()).Replace("{1}", UserData.Instance.battleFriend.name);
					popup.addFriendObject.SetActive(true);
				}
			}

			UserData.Instance.isOpenNewBossAreaForGStar = true;
			UserData.Instance.isExistRaidBoss = false;
		}

		public void ShowBattleLose()
		{
			SoundController.PlayBGM("BGM_Battle_Lose", false);

			GameObject popupPrefab = ResourceLoader.Load("Prefab/UI/battle_result_popup_04") as GameObject;
			BattleResultPopup popup = (Instantiate(popupPrefab) as GameObject).GetComponent<BattleResultPopup>();
			popup.transform.parent = transform.parent;
			popup.transform.localScale = Vector3.one;
			popup.transform.localPosition = new Vector3(0f, 0f, 0f);
			if (UserData.Instance.raidBossResultData != null)
				popup.legionExpLabel.text = string.Format("+{0}", UserData.Instance.raidBossResultData.legionExp.ToString());
			//(지스타 임시) 임시테이블에 따라 보상 표시
			popup.legionExpLabel.text = string.Format("+0");
			if (UserData.Instance.battleFriendId == 0)
			{
				popup.addFriendObject.SetActive(false);
				popup.friendRewardObject.SetActive(false);
				popup.GetComponent<Animation>().Play("Battle_Result_Bonus_failed EPNF");
			}
			else
			{
				if (UserData.Instance.battleFriendIsMyFriend)
				{
					popup.addFriendObject.SetActive(false);
					popup.friendRewardObject.SetActive(true);
				}
				else
				{
					popup.addFriendLabel.text = TextController.GetStringWithId("uiPopupFriendCaution1").Replace("{0}", UserData.Instance.battleFriend.lv.ToString()).Replace("{1}", UserData.Instance.battleFriend.name);
					popup.addFriendObject.SetActive(true);
					popup.friendRewardObject.SetActive(false);
				}
				popup.GetComponent<Animation>().Play("Battle_Result_Bonus_failed EPWF");
			}

			UserData.Instance.isOpenNewBossAreaForGStar = false;
		}
	}
}
